#include <map>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string.h>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>

#include "log.hpp"

#define sockfpdefalut -1
#define defalut "0.0.0.0"
Log lg;

enum Eror
{
    ERROR_SOCKET = 1,
    ERROR_BIND,
    ERROR_RUN,
    ERROR_RECV,
    OPEN_CILENT,
    ERROR_READFP,
    ERROR_REVEFROM_SERVER,
    ERROR_REVEFROM_CILENT
};

class Userver
{
public:
    Userver(uint16_t port = 8088, const std::string ip = defalut, int sockfp_ = sockfpdefalut)
    :port_(port), ip_(ip)
    {}

    void Init()
    {
        sockfp_ = socket(AF_INET, SOCK_DGRAM, 0);
        if(sockfp_ < 0)
        {
            lg(Fatal,"创建套接字失败: %s, errno: %d", strerror(errno), errno);
            exit(ERROR_SOCKET);
        }
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        socklen_t len = sizeof(server);
        server.sin_port = htons(port_);  //设置端口号
        inet_aton(ip_.c_str(), &server.sin_addr); //设置ip
        int bindresult = bind(sockfp_, (const sockaddr*)&server, len);
        if(bindresult < 0)
        {
            lg(Fatal,"绑定端口号和ip失败: %s, errno: %d", strerror(errno), errno);
            exit(ERROR_BIND);
        }
        isrunning = true;
        lg(Info, "ServerCreate Ready");
    }

    void Run()
    {
        if(isrunning != true){exit(ERROR_RUN);}
        while(true)
        {
            struct sockaddr_in cilentdata;
            bzero(&cilentdata, sizeof(cilentdata));
            socklen_t len = sizeof(cilentdata);
            char buffer[1024];
            int size = recvfrom(sockfp_, buffer, 1023, 0, (sockaddr*)&cilentdata, &len);
            if(size < 0)
            {
                lg(Fatal,"无法接收到客户端的信息: %s, errno: %d", strerror(errno), errno);
                exit(ERROR_REVEFROM_CILENT);
            }
            buffer[size] = 0;
            //希望在接收客户端的报文之后，能够打印到自己的屏幕上

            char* cilentip;                           //是指向inet_ntoa里一个静态成员的指针
            cilentip = inet_ntoa(cilentdata.sin_addr);//会将sin_addr从网络字序转为本地字序并保存到自己封装的一个静态成员里(后续再调用这个函数，如果是多线程那么会有线程安全的问题)
            std::cout << "IP[ " <<  cilentip << "] " << " messages : " << buffer;
            //存储一下用户的个人信息(目前用ip地址替代)
            users.insert({cilentip, cilentdata});
            //接收到数据后，给每个客户端发送一个广播，让客户端看到其他不同客户端的信息
            boradcast(buffer, cilentdata);
        }
    }

    void boradcast(const char* buffer, const sockaddr_in thiscilentdata)
    {
        string message;
        message += "IP[ ";
        message += inet_ntoa(thiscilentdata.sin_addr);
        message += "]: ";

        for(auto &e : users)
        {
            socklen_t len = sizeof(e.second);
            message += buffer;
            sendto(sockfp_, message.c_str(), message.size(), 0, (const sockaddr*)&e.second, len);
            
        }
    }

    ~Userver()
    {}
private:
    uint16_t port_;
    std::string ip_;
    int sockfp_;
    bool isrunning = 0;
    std::map<char*, sockaddr_in> users; //将每个客户端的报文结构体存储在一个map里,key存的是ip地址，value存的是用户id(暂时如此设计)
};